package obecto.task.container
{
	import obecto.event.TaskEvent;
	import obecto.event.TaskEventKind;
	import obecto.task.IInterruptibleTask;
	import obecto.task.ITask;

	[Event(name="interrupt", type="obecto.event.TaskEvent")]

	public class InterruptibleSequence extends Sequence implements IInterruptibleTask
	{
		protected var _reversing : Boolean = false;
		
		public function InterruptibleSequence(aTasks : Array = null)
		{
			super(aTasks);
		}	
		
		public function end() : void
		{
			_reversing = false;
			
			if(running == true)
			{
				removeRunningTaskCompleteListener();		
				dispatchEvent(new TaskEvent(TaskEvent.INTERRUPT, TaskEventKind.END));
			}
			
			var index : int = running ? _runningTaskIndex : 0;
			
			for (var i : int = index; i < _tasks.length; i++)
			{
				(_tasks[i] as IInterruptibleTask).end();
			}
			
			complete();
		}
		
		public function interrupt() : void
		{
			if(running == true)
			{	
				removeRunningTaskCompleteListener();
				
				(_tasks[runningTaskIndex] as IInterruptibleTask).interrupt();

				_running = false;
				_reversing = false;	
				_runningTaskIndex = -1;
				
				dispatchEvent(new TaskEvent(TaskEvent.INTERRUPT, TaskEventKind.INTERRUPT));
			}
		}
		
		public function reverse() : void
		{
			if(reversing == false)
			{	
				_reversing = true;
				
				if(running == true)
				{	
					dispatchEvent(new TaskEvent(TaskEvent.INTERRUPT, TaskEventKind.REVERSE));
					
					(_tasks[runningTaskIndex] as IInterruptibleTask).reverse();
				}
				else
				{
					_running = true;
					_runningTaskIndex = _tasks.length;
					
					dispatchEvent(new TaskEvent(TaskEvent.START, TaskEventKind.REVERSE));					
					
					runNextTask();
				}
			}
		}
		
		public function forward() : void
		{
			if(_running == true && _reversing == true)
			{
				_reversing = false;
				
				dispatchEvent(new TaskEvent(TaskEvent.START, TaskEventKind.FORWARD));
				
				(_tasks[runningTaskIndex] as IInterruptibleTask).forward();
			}
		}
		
		public function rollback() : void
		{
			_reversing = true;
			
			if(_running == true)
			{	
				removeRunningTaskCompleteListener();
				
				dispatchEvent(new TaskEvent(TaskEvent.INTERRUPT, TaskEventKind.ROLLBACK));
			}
			
			var index : int = running ? _runningTaskIndex : (_tasks.length - 1);
			
			for (var i : int = index; i >= 0; i--)
			{
				(_tasks[i] as IInterruptibleTask).rollback();
			}
				
			completeReverse();
		}
		
		public function get reversing() : Boolean
		{
			return _reversing;
		}
		
		override public function addTaskAt(task : ITask, index : int) : void
		{	
			assertObjectIsInterruptibleTask(task);
			
			super.addTaskAt(task, index);
		}
		
		override public function addTask(task : ITask) : void
		{
			assertObjectIsInterruptibleTask(task);
			
			super.addTask(task);
		}
		
		override public function set tasks(value : Array) : void
		{			
			for each(var object : Object in value)
			{
				assertObjectIsInterruptibleTask(object);
			}
			
			super.tasks = value;
		}
		
		virtual public function captureStartValues(overrideExplicit : Boolean = false) : void
		{
		}
				
		protected function completeReverse() : void
		{
			_running = false;
			_reversing = false;
			_runningTaskIndex = -1;
			
			dispatchEvent(new TaskEvent(TaskEvent.COMPLETE, TaskEventKind.REVERSE))			
		}
		
		override protected function getRunningTaskIndexAfterDeletion() : int
		{
			if(_reversing == false)
			{
				return super.getRunningTaskIndexAfterDeletion();
			}
			else
			{
				return _runningTaskIndex;
			}
		}
		
		override protected function getNextTaskIndex() : int
		{
			if(_reversing == false)
			{
				return super.getNextTaskIndex();
			}
			else
			{
				return _runningTaskIndex - 1;
			}
		}
		
		override protected function getTerminatingIndex() : int
		{
			if(_reversing == false)
			{
				return super.getTerminatingIndex();
			}
			else
			{			
				return -1;
			}
		}
		
		override protected function run() : void
		{
			if(_reversing == false)
			{
				super.run();
			}
			else
			{
				reverse();
			}
		}
		
		override protected function finish() : void
		{
			if(_reversing == false)
			{
				super.finish();
			}
			else
			{
				completeReverse();
			}
		}
		
		override protected function runTask(task : ITask) : void
		{
			if(_reversing == false)
			{
				super.runTask(task);
			}
			else
			{
				(task as IInterruptibleTask).reverse();
			}
		}			
		
		protected function assertObjectIsInterruptibleTask(object : Object) : void
		{
			if((object is IInterruptibleTask) == false)
			{
				throw new Error("Object isn't interruptible task.");
			}			
		}
	}
}